package com.aim.analysis.excel;

import com.aim.analysis.artifact.AbstractArtifact;
import com.aim.analysis.artifact.ArtifactSubFolder;
import com.aim.analysis.questionnaire.QValueExtractor;
import com.aim.analysis.questionnaire.QuestionnaireRecord;
import com.aim.analysis.records.*;
import com.aim.azure.AzureConnection;
import com.aim.util.extractors.ValueExtractor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

/**
 * User: Avraham Shvartzon
 * Date: 6/17/14
 */
public class ExperimentReport extends AbstractArtifact{

    private String fileName;

    public ExperimentReport(String fileName) {
        this.fileName = fileName;
    }

    @Override
    public boolean execute(Collection<Hit> hitCollection) throws Exception {
        File artifactFolder = getArtifactFolder();
            write(new File(artifactFolder, fileName + ".xlsx"), hitCollection);
            return true;
    }

    @Override
    protected String getFileNameSuffix() {
        return "";
    }

    public ArtifactSubFolder getArtifactSubFolder(){
        return ArtifactSubFolder.RECORD_PER_GAME;
    }

    public void write(File reportFile, Collection<Hit> hits) throws Exception {
        XSSFWorkbook workbook = new XSSFWorkbook();

        writeGameSummeryReport(workbook, hits);
        writeQuestionsReport(workbook, hits);

        workbook.write(new FileOutputStream(reportFile));
    }

    private void writeGameSummeryReport(XSSFWorkbook workbook, Collection<Hit> hits) {
        List<GameValueExtractor> gameExtractors = getGameExtractors();
        List<Game> games = HitUtil.flattGames(hits);
        XSSFSheet sheet = workbook.createSheet("Game Summery");
        writeTable(sheet, gameExtractors, games);
        addGameImageLink(sheet, workbook, games);
    }

    private void addGameImageLink(XSSFSheet sheet, XSSFWorkbook wb,  List<Game> games) {
        Font hlink_font = wb.createFont();
        hlink_font.setUnderline(Font.U_SINGLE);
        hlink_font.setColor(IndexedColors.BLUE.getIndex());
        CellStyle hlink_style = wb.createCellStyle();
        hlink_style.setFont(hlink_font);

        for (int i = 0; i < games.size(); i++) {
            Game game = games.get(i);
            XSSFRow row = sheet.getRow(i+1);
            XSSFCell cell = row.getCell(0);

            Hyperlink link = wb.getCreationHelper().createHyperlink(Hyperlink.LINK_FILE);
            link.setAddress(game.getImageFileName());

            cell.setHyperlink(link);
            cell.setCellStyle(hlink_style);
        }
    }

    private static List<GameValueExtractor> getGameExtractors() {
        List<GameValueExtractor> valueExtractors = new ArrayList<GameValueExtractor>();

        // header
        valueExtractors.add(GameValueExtractor.partitionKey);
        valueExtractors.add(GameValueExtractor.gameDescription);
        valueExtractors.add(GameValueExtractor.gameNumber);

        //mechanical - actions & costs
        valueExtractors.add(GameValueExtractor.maintenance);
        valueExtractors.add(GameValueExtractor.minor);
        valueExtractors.add(GameValueExtractor.moderate);
        valueExtractors.add(GameValueExtractor.severe);
        valueExtractors.add(GameValueExtractor.maintenanceCost);
        valueExtractors.add(GameValueExtractor.repairCost);
        valueExtractors.add(GameValueExtractor.mechanicalCost);

        valueExtractors.add(GameValueExtractor.mntAfterAlertDelayMean);
        valueExtractors.add(GameValueExtractor.mntAfterAlertDelayVar);
        valueExtractors.add(GameValueExtractor.numOfMaintenanceAfterAlert);
        valueExtractors.add(GameValueExtractor.malfunctionAfterAlertDelayMean);
        valueExtractors.add(GameValueExtractor.malfunctionAfterAlertDelayVar);
        valueExtractors.add(GameValueExtractor.numOfMalfunctionAfterAlert);
        valueExtractors.add(GameValueExtractor.firstEventAfterAlertDiff);

        //refuel - actions & costs
        valueExtractors.add(GameValueExtractor.refuelByStations);
        valueExtractors.add(GameValueExtractor.refuelByStationsCost);
        valueExtractors.add(GameValueExtractor.refuelBySpaceship);
        valueExtractors.add(GameValueExtractor.refuelBySpaceshipCost);
        valueExtractors.add(GameValueExtractor.totalRefuelCost);

        //time
        valueExtractors.add(GameValueExtractor.mechanicalTime);
        valueExtractors.add(GameValueExtractor.refuelBySpaceshipTime);
        valueExtractors.add(GameValueExtractor.freezeTime);


        //performance
        valueExtractors.add(GameValueExtractor.totalShutdown);
        valueExtractors.add(GameValueExtractor.totalCollision);
        valueExtractors.add(GameValueExtractor.totalFire);
        valueExtractors.add(GameValueExtractor.calculatedMechanicalCost);
        valueExtractors.add(GameValueExtractor.netScore);

        // score
        valueExtractors.add(GameValueExtractor.score);
        valueExtractors.add(GameValueExtractor.calculatedScore);

        return valueExtractors;
    }

    private static List<QValueExtractor> getQuestionnaireExtractors(){
        List<QValueExtractor> extractors = new LinkedList<QValueExtractor>();

        extractors.add(QValueExtractor.partitionKey);
        extractors.add(QValueExtractor.gender);
        extractors.add(QValueExtractor.age);
        extractors.add(QValueExtractor.enjoyGame);
        extractors.add(QValueExtractor.performanceSelfAssessment);
        extractors.add(QValueExtractor.alertFrequency);
        extractors.add(QValueExtractor.setFrequency);
        extractors.add(QValueExtractor.secondsInAdvanceForAlert);
        extractors.add(QValueExtractor.maintenanceAlertsHelpful);
        extractors.add(QValueExtractor.gameStrategyDesc);
        extractors.add(QValueExtractor.takeRisks);
        extractors.add(QValueExtractor.bugsOccured);
        extractors.add(QValueExtractor.bugDescriptionIfExist);
        extractors.add(QValueExtractor.freeText);

        return extractors;
    }

    public void writeQuestionsReport(XSSFWorkbook workbook, Collection<Hit> hits){
        List<QValueExtractor> questionnaireExtractors = getQuestionnaireExtractors();
        List<QuestionnaireRecord> questionnaireRecords = HitUtil.getQuestionnaireRecords(hits);
        XSSFSheet sheet = workbook.createSheet("Questions");
        writeTable(sheet, questionnaireExtractors, questionnaireRecords );
    }

    public static <A extends ValueExtractor<T,? extends Object>,T> void writeTable(XSSFSheet sheet, List<A> extractors, List<T> objectLists){
        int rowIndex = 0;
        int cellIndex = 0;
        XSSFRow header = sheet.createRow(rowIndex++);

        for (ValueExtractor extractor : extractors) {
            XSSFCell cell = header.createCell(cellIndex++);
            cell.setCellValue(extractor.name);
        }

        for (T objectList : objectLists) {
            cellIndex = 0;
            XSSFRow row = sheet.createRow(rowIndex++);
            for (ValueExtractor extractor : extractors) {
                XSSFCell cell = row.createCell(cellIndex++);
                Object value = extractor.getValue(objectList);
                cell.setCellValue(value != null? value.toString() : "N/A");
            }
        }

    }

    public static void main(String[] args) throws Exception {
        File reportFolder = new File("C:\\data\\Thesis\\spacegame\\resultAzure\\xlsReports");
        //File reportFile = new File(reportFolder, "2014_06_16-19.xlsx");
        //File reportFile = new File(reportFolder, "2014_06_16-28_with_alert.xlsx");
        //File reportFile = new File(reportFolder, "2014_06_16-28 mechanicalCalculatedCost players.xlsx");
        File reportFile = new File(reportFolder, "test1.xlsx"); //3QXNC7EIPIWAJL3HSFEYL2MJH6D09A
        AzureConnection azureConnection = new AzureConnection();
        azureConnection.connect();
        //azureConnection.addExperimentDate("20140616");
        //azureConnection.addExperimentDate("20140619");
        //azureConnection.addExperimentDate("20140714");
        azureConnection.addExperimentDate("Test");

        GameMap gameMap = new GameMap();
        List<Hit> hits = Hit.createHits(gameMap, azureConnection);

        ExperimentReport experimentReport = new ExperimentReport("test");
        experimentReport.write(reportFile, hits);

    }
}
